#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <omp.h>

int isPalindrome (char * str)
{
    int i, len = strlen(str), lim = len/2, res = 1;
    for (i = 0; i < lim; i++)
    {
        if ( str[i] != str[len-1-i])
        {
            res = 0;
            break;
        }
    }
    return res;
}

void strToAlNumLower (char * str)
{
    char * it1, * it2;
    it1 = it2 = str;
    while (*it1 != '\0')
    {
        if (isalnum(*it1) || *it1 == ' ')
        {
            if (*it1 >= 'A' && *it1 <= 'Z')
                *it1 = *it1 + 'a' - 'A';
            *it2++ = *it1++;
        }
        else it1++;
    }
    *it2 = '\0';
}

int main (void)
{
    int palindromic_phrases = 0, palindromic_words = 0;
    int i, j, phrases_count, bpoint, read_size;
    char ** buffer, ** bufferc, ** word_buffer, * wbuffer;
    char * it1, * it2;
    FILE * f = fopen("shakespeare.txt", "r");
    
    if (f == NULL) { printf("Erro na leitura do arquivo!\n"); return 1; }
    
    while (fscanf(f, "%*[^\r\n]%*[\r\n]") != EOF)
        phrases_count++;
    phrases_count++;
    rewind(f);
    
    buffer = (char **) malloc(phrases_count * sizeof(char *));
    for (i = 0; i < phrases_count; i++)
        buffer[i] = (char *) malloc(1000 * sizeof(char));
    
    bufferc = (char **) malloc(phrases_count * sizeof(char *));
    for (i = 0; i < phrases_count; i++)
        bufferc[i] = (char *) malloc(1000 * sizeof(char));
    
    word_buffer = (char **) malloc(914530 * sizeof(char *));
    for (i = 0; i < 914530; i++)
        word_buffer[i] = (char *) malloc(1000 * sizeof(char));
    
    wbuffer = (char *) malloc(1000 * sizeof(char));
    
    for (i = 0; fscanf(f, "%[^\r\n]%*[\r\n]", buffer[i]) != EOF; i++)
    {
        strToAlNumLower(buffer[i]);
        strcpy(bufferc[i], buffer[i]);
        it1 = it2 = bufferc[i];
        while (*it1 != '\0')
        {
            if (!isalnum(*it1)) it1++;
            else *it2++ = *it1++;
        }
        *it2 = '\0';
    }
    
    double start = omp_get_wtime();
    
    #pragma omp parallel for reduction(+:palindromic_phrases)
    for (i = 0; i < phrases_count; i++)
    {
        if (bufferc[i][0] != '\0' && isPalindrome(bufferc[i]))
        {
            palindromic_phrases++;
            printf("%s\n", bufferc[i]);
        }
    }
    
    double end = omp_get_wtime();
    printf("Tempo para calcular as frases: %lf\n", end - start);
    j = 0;
    for (i = 0; i < phrases_count; i++)
    {
        bpoint = 0;
        while (sscanf(buffer[i] + bpoint, "%s%n", wbuffer, &read_size) != EOF)
        {
            bpoint += read_size;
            if (wbuffer[0] != '\0')
                strcpy(word_buffer[j++], wbuffer);
        }
    }
    
    start = omp_get_wtime();
    
    #pragma omp parallel for reduction(+:palindromic_words)
    for (i = 0; i < j; i++)
    {
        if (isPalindrome(word_buffer[i]))
        {
            palindromic_words++;
            printf("%s\n", word_buffer[i]);
        }
    }
    
    end = omp_get_wtime();
    
    printf("Tempo para calcular as palavras: %lf\n", end - start);
    
    printf("%d\n%d\n", palindromic_phrases, palindromic_words);
    
    fclose(f);
    for (i = 0; i < phrases_count; i++)
        free(bufferc[i]);
    free(bufferc);
    for (i = 0; i < phrases_count; i++)
        free(buffer[i]);
    free(buffer);
    for (i = 0; i < 914530; i++)
        free(word_buffer[i]);
    free(word_buffer); 
    free(wbuffer); 
    
    return 0;
}
